package club.gskj.gulimall.search.thread;

import rx.Completable;

import javax.sound.midi.Soundbank;
import java.util.concurrent.*;

/**
 * @ClassName ThreadTest
 * @Description TODO 异步线程
 * @Author 康纳
 * @Date 2021-03-09
 */


public class ThreadTest {
    public static ExecutorService executorService = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main....start");

        // 创建异步任务
        //CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
        //    System.out.println("当前线程 " + Thread.currentThread().getId());
        //    int i = 10 / 2;
        //    System.out.println("运行结果 " + i);
        //}, executorService);
        //
        //CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
        //    System.out.println("当前线程 " + Thread.currentThread().getId());
        //    int i = 10 / 0;
        //    System.out.println("运行结果 " + i);
        //    return i;
        //}, executorService).whenComplete((res,exception)->{
        //    // whenComplete 能得到异常信息，无法修改返回值
        //    System.out.println("异步任务执行完成  "+res+"; 异常结果为 "+exception);
        //}).exceptionally(throwable->{
        //    // 感知异常、同时返回默认值
        //    return 10;
        //});

        /**
         * 方法执行完后的处理
         */
        //CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
        //    System.out.println("当前线程 " + Thread.currentThread().getId());
        //    int i = 10 / 0;
        //    System.out.println("运行结果 " + i);
        //    return i;
        //}, executorService).handle((res,throwable)->{
        //    // handle 执行完后的处理，无论成功失败
        //    if(res != null){
        //        return  res * 2;
        //    }
        //    if(throwable!=null){
        //        return 0;
        //    }
        //    return 0;
        //});
        //R apply(T t, U u);
        // 获取返回值
        //Integer integer = integerCompletableFuture.get();
        //System.out.println(integer);

        /**
         * 线程串行化
         * thenRun 不能获取上一步的执行结果,无返回值
         * .thenRunAsync(() -> {
         *             System.out.println("任务2执行");
         *         }, executorService);
         *
         * thenAcceptAsync:能接受上一步结果,无返回值
         *
         * thenApplyAsync 能接受上一步结果,有返回值
         */
        //CompletableFuture<Object> future = CompletableFuture.supplyAsync(() -> {
        //    System.out.println("当前线程 " + Thread.currentThread().getId());
        //    int i = 10 / 4;
        //    System.out.println("运行结果 " + i);
        //    return i;
        //}, executorService).thenApplyAsync(res->{
        //    System.out.println("任务2执行  "+res);
        //    return res+"s";
        //},executorService);
        //// future.get(); 阻塞式调用
        //Object o = future.get();
        //System.out.println(o);

        /***
         *  两任务同时执行
         */
        //CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> {
        //    System.out.println("当前线程1开始" + Thread.currentThread().getId());
        //    int i = 10 / 4;
        //    System.out.println("当前线程1结束" + i);
        //    return i;
        //}, executorService);
        //
        //CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
        //    System.out.println("当前线程2开始" + Thread.currentThread().getId());
        //    try {
        //        Thread.sleep(3000);
        //    } catch (InterruptedException e) {
        //        e.printStackTrace();
        //    }
        //    System.out.println("当前线程2结束 ");
        //    return "hello";
        //}, executorService);

        // 组合 任务1 +任务2 执行完, 再执行任务3
        //future1.runAfterBothAsync(future2,()->{
        //    System.out.println("任务3开始...");
        //},executorService);


        //  void accept(T t, U u);
        //future1.thenAcceptBothAsync(future2,(arge1,arge2)->{
        //    System.out.println("任务3开始...返回的结果 "+arge1+"--"+arge2);
        //},executorService);

        // R apply(T t, U u);
        //CompletableFuture<String> future = future1.thenCombineAsync(future2, (f1, f2) -> {
        //    // 返回结果, f1:future1的结果 f2:future2的结果
        //    return f1 + " -- " + f2;
        //}, executorService);

        //String s = future.get();
        //System.out.println(s);

        /**
         * 两个任务。只要有一个任务完成就执行任务3
         *
         * runAfterEitherAsync 不感知结果，无返回值
         * acceptEitherAsync 感知结果，无返回值
         * applyToEitherAsync 感知结果，有返回值
         */

        //future1.runAfterEitherAsync(future2, () -> {
        //    System.out.println("任务3 执行....");
        //}, executorService);
        //
        //void accept(T t);
        //future1.acceptEitherAsync(future2, (res) -> {
        //    System.out.println("任务3 执行...." + res);
        //}, executorService);
        //
        // R apply(T t);
        //CompletableFuture<String> future = future1.applyToEitherAsync(future2, (res) -> {
        //    System.out.println("任务3 执行...." + res);
        //    return res + " hello";
        //}, executorService);
        //System.out.println(future.get());

        /**
         *  多任务执行
         */
        //CompletableFuture<Object> futureImg = CompletableFuture.supplyAsync(() -> {
        //    System.out.println("查询商品图片信息");
        //    return "hello.jpg";
        //}, executorService);
        //CompletableFuture<Object> futureAttr = CompletableFuture.supplyAsync(() -> {
        //    System.out.println("查询商品属性");
        //    return "紫色 256G+8G";
        //}, executorService);
        //
        //CompletableFuture<Object> futureDesc = CompletableFuture.supplyAsync(() -> {
        //
        //    try {
        //        Thread.sleep(3000);
        //    } catch (InterruptedException e) {
        //        e.printStackTrace();
        //    }
        //    System.out.println("查询商品简介");
        //    return "华为Meta30Pro";
        //}, executorService);

        // 阻塞式执行
        //futureImg.get();
        //futureAttr.get();
        //futureDesc.get();

        //所有任务都必须执行完
        //CompletableFuture<Void> future = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
        //future.get();

        // 只要有一个任务执行就行
        //CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
        // 等待所有结果完成

        //System.out.println("main....end" + futureImg.get() + futureAttr.get() + futureDesc.get());
        //System.out.println("main....end" + future.get());
    }

    /**
     * 1. 继承Thread
     * Thread01 thread01 = new Thread01();
     * thread01.start();
     * <p>
     * 2. 实现Runnable接口
     * Runable01 runable01 = new Runable01();
     * new Thread(runable01).start();
     * <p>
     * 3. 实现Callable接口+FutrueTask(可以按到返回结果，可以处理异常)
     * Callable01 callable01 = new Callable01();
     * FutureTask<Object> objectFutureTask = new FutureTask<>(callable01);
     * new Thread(objectFutureTask).start();
     * // 等待整个线程执行完成，获取返回结果 (阻塞式)
     * Object o = objectFutureTask.get();
     * <p>
     * 4. 线程池
     * 给线程池提交任务
     * //executorService.execute(new Runable01());
     * // 以后在业务代码中，1，2，3方式都不能使用，容易浪费服务资源
     * // TOOD 应该让多线程的异步任务都交给线程池执行
     * //new Thread(() -> System.out.println("ss")).start();
     * // 创建线程池，保证当前系统中有1.。2个池，每个异步任务直接提交到线程池去执行
     * 1.创建：[ExecutorService]
     * 1.1 Executors
     * <p>
     * 1.2
     * 区别： 1，2 无法得到线程返回值； 3可以得到结果。
     * 1，2，3都不能控制线程资源。
     * 4.可以控制资源。整个系统的性能稳定。
     * <p>
     * Futrue可以结构异步执行的返回结果
     */
    public void threadTest(String[] args) throws ExecutionException, InterruptedException {

        System.out.println("main .....start");

        //executorService.execute(new Runable01());
        /**
         * 七大参数
         *  corePoolSize：[5]核心线程数[会一直存在，除非设置了超时 allowCoreThreadTimeOut]；线程池创建好以后准备就绪的线程数量，等待来接受异步任务并执行
         *     5个， Thread thread = new Thread();  thread.start();
         *  maximumPoolSize[200]: 最大线程数量，用于控制资源
         *  keepAliveTime： 存活时间。当前线程数量大于核心数量，会释放空闲的线程。
         *          释放空闲的线程(maximumPoolSize-corePoolSize)，只要线程空闲时间大于指定的超时时间；
         *  TimeUnit: 时间单位
         *  BlockingQueue<Runnable> workQueue:阻塞队列。如果目前任务很多，将线程没处理到的任务放入队列里面，
         *          等待有空闲线程时，就会去队列中取出新的任务并执行。
         *  threadFactory：线程的创建工厂
         *  RejectedExecutionHandler handler：如果队列满了，按照指定的拒绝策略，拒绝过多的任务。
         *
         *  工作顺序；
         *      1. 线程池创建好，准备好Core数量的核心线程，等待接受任务
         *      2. Core线程满了，就将再进来的任务放入阻塞队列中，等空闲core线程自己去阻塞队列中获取任务并执行
         *      3. 阻塞队列也满了，直接开新线程执行，最大只能开大max指定的数量
         *      4. max，就是用指定的RejectedExecutionHandler拒绝策略，拒绝执行任务。
         *      5. max执行完成，有很多空闲线程，在指定的存货时间以后，就会释放多余的(max-core)的线程
         *                          new LinkedBlockingDeque<>() 最大数量为默认Integer的最大值，会导致内存不够
         *
         *       一个线程池，core7; max20; queue50; 100并发进来如何分配;
         *       7会立即执行
         *       50 会进入队列
         *       再开13个线程执行
         *       剩下的30个，使用拒绝策略执行，一般为丢弃
         *       如果不想丢弃，使用CallerRunsPolicy 同步执行。
         */
        //ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,
        //        200,
        //        10,
        //        TimeUnit.SECONDS,
        //        new LinkedBlockingDeque<>(100000),
        //        Executors.defaultThreadFactory(),
        //        new ThreadPoolExecutor.AbortPolicy());

        // 缓存线程池，core是0，所有都可回收
        //Executors.newCachedThreadPool();

        // 固定大小线程数量池。core=最大的，都不可收回
        //Executors.newFixedThreadPool(20);

        // 定时任务的线程池
        // Executors.newScheduledThreadPool()

        // 单线程的线程池，core1 max1.后台从队列中获取任务。挨个执行。
        //Executors.newSingleThreadExecutor();


        System.out.println("main .....end ");
    }


    public static class Thread01 extends Thread {
        @Override
        public void run() {
            System.out.println("当前线程 " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果 " + i);
        }
    }

    public static class Runable01 implements Runnable {

        @Override
        public void run() {
            System.out.println("当前线程 " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果 " + i);
        }
    }

    public static class Callable01 implements Callable<Object> {

        @Override
        public Object call() throws Exception {
            System.out.println("当前线程 " + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果 " + i);
            return i;
        }
    }
}
